package net.entelijan.cobean.tree;

import java.awt.Component;
import java.util.List;

import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import net.entelijan.cobean.core.ColumnDesc;
import net.entelijan.cobean.core.IInitializer;
import net.entelijan.cobean.core.ISingleSelectionCobean;
import net.entelijan.cobean.util.CobeanUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class RecursiveTreeInitializer<T> extends
		AbstractTreeInitializer implements
		IInitializer<ISingleSelectionCobean<T>> {

	private static Log log = LogFactory
			.getLog(RecursiveTreeInitializer.class);

	private String childrenMethodName;

	private List<ColumnDesc> columnDescs;

	private IIconMapper<T> iconMapper;

	public RecursiveTreeInitializer() {
		super();
	}

	@Override
	public ISingleSelectionCobean<T> initialize() {
		commonInit();
		return new ISingleSelectionCobean<T>() {

			private T value;

			private TreeState treeState = new TreeState();

			private T selectedValue;

			@Override
			public T getSelectedValue() {
				return selectedValue;
			}

			@Override
			public void setSelectedValue(T value) {
				log.info("[setSelectedValue] value='" + value + "'");
				TreePath selectionPath = createTreePath(value);
				coTree.setSelectionPath(selectionPath);
				coTree.scrollPathToVisible(selectionPath);
			}

			@Override
			public T getValue() {
				return this.value;
			}

			@Override
			public void setValue(T value) {
				this.value = value;
				TreeModel treeModel = createTreeModel(value,
						new RecursiveTreeLevelDescription());
				coTree.setCellRenderer(new CobeanTreeCellRenderer());
				treeState.restore(treeModel);
				treeModel.addTreeModelListener(treeState);
				coTree.setModel(treeModel);
				coTree.getSelectionModel().setSelectionMode(
						TreeSelectionModel.SINGLE_TREE_SELECTION);
				coTree.addTreeSelectionListener(new TreeSelectionListener() {

					@SuppressWarnings("unchecked")
					@Override
					public void valueChanged(TreeSelectionEvent e) {
						TreePath path = e.getPath();
						selectedValue = (T) path.getLastPathComponent();
					}

				});
			}

		};
	}

	private class RecursiveTreeLevelDescription implements
			ITreeLevelDescription {

		public RecursiveTreeLevelDescription() {
			super();
		}

		public ITreeLevelDescription getChildDescription() {
			return this;
		}

		@SuppressWarnings("unchecked")
		@Override
		public Component getTreeCellRendererComponent(Object model,
				DefaultTreeCellRenderer defaultComp, boolean sel,
				boolean expanded, boolean leaf, int row, boolean hasFocus) {
			String text = CobeanUtil.createText(model, columnDescs);
			defaultComp.setText(text);
			if (iconMapper != null) {
				defaultComp.setIcon(iconMapper.getIcon((T) model));
			}
			return defaultComp;
		}

		@Override
		public <U> List<U> getChildren(U value) {
			return CobeanTreeUtil.getChildren(value, childrenMethodName);
		}
	}

	public String getChildrenMethodName() {
		return childrenMethodName;
	}

	public void setChildrenMethodName(String childrenMethodName) {
		this.childrenMethodName = childrenMethodName;
	}

	public List<ColumnDesc> getColumnDescs() {
		return columnDescs;
	}

	public void setColumnDescs(List<ColumnDesc> columnDescs) {
		this.columnDescs = columnDescs;
	}

	public IIconMapper<T> getIconMapper() {
		return iconMapper;
	}

	public void setIconMapper(IIconMapper<T> iconMapper) {
		this.iconMapper = iconMapper;
	}

}
